package clustering.implementations;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;



import clustering.framework.*;

public class MaximumLikelihoodEvaluator implements IEvaluator{
	double bestScore = Double.NEGATIVE_INFINITY;
	double absoluteBestScore = Double.NEGATIVE_INFINITY;
	int [] absoluteBestNodes = null;
	String absoluteBestTree = null; 
	static String getUniqueCode(int k){
		String code = "";
		char [] digits = {'a','b','c','d','e','f','g','h','i','j'};
		for(int i=0;i<5;i++){
			code = digits[k%10] + code;
			k = k/10;
		}
		return code;
	}
	public int [] getAbsoluteBestNodes()
	{
		return this.absoluteBestNodes;
	}
	public void resetBestScore()
	{
		bestScore = Double.NEGATIVE_INFINITY;
	}
	public double getOptimalScore()
	{
		return 0;
	}
	public boolean evaluateBetter(String tree, String [] filesList, int [] nodes) throws Exception{
		
		for(int i=filesList.length-1;i>=0;i--){
			tree = tree.replaceAll(i + "",getUniqueCode(i));
	    }
	    for(int i=filesList.length-1;i>=0;i--){
	    	tree = tree.replaceAll(getUniqueCode(i), filesList[i].substring(filesList[i].lastIndexOf("\\")+1));
	    }
		
		FileOutputStream fos = new FileOutputStream("intree");
		fos.write(tree.getBytes());
		fos.close();
		
		String fitchCmd = "dnaml_b.bat";
	    Runtime runtime = Runtime.getRuntime();
		Process proc = runtime.exec(fitchCmd);
		debugProcess(proc);
		
		double score = selectBestMLTree("outfile");
		//System.out.println("New score = " + score);
		if(score >= bestScore)
		{
			//System.out.println("Better tree found with score = " + score);
			bestScore = score;
			if(bestScore >= absoluteBestScore)
			{
				absoluteBestScore = bestScore;
				absoluteBestTree = tree;
				absoluteBestNodes = new int[nodes.length];
				for(int i=0;i<nodes.length;i++)
				{
					absoluteBestNodes[i] = nodes[i];
				}
			}
			
			return true;
		}
		return false;
	}

	public double getBestScore() {
		return bestScore;
	}
	
	public double getAbsoluteBestScore()
	{
		return absoluteBestScore;
	}
	
	public String getAbsoluteBestTree()
	{
		return absoluteBestTree;
	}
	
	double selectBestMLTree(String outFile)throws Exception
	{
		File f = new File(outFile);
		FileInputStream fis = new FileInputStream(f);
		byte [] data = new byte[(int)f.length()];
		fis.read(data);
		fis.close();
		String sMatrix = new String(data);
		StringTokenizer stLines = new StringTokenizer(sMatrix,"\n\r");
		
		while(stLines.hasMoreTokens()){
			String line = stLines.nextToken();
			if(line.indexOf("Ln Likelihood =")!=-1)
			{
				StringTokenizer number = new StringTokenizer(line," ");
				number.nextToken();
				number.nextToken();
				number.nextToken();
				double like = Double.parseDouble(number.nextToken());
				
				//System.out.println("like = " + like);
				
				return like;
			}
		}
		//System.out.println("Tree with lsq = "+min_ssq);
		return Double.NEGATIVE_INFINITY;
	}
	
	static void debugProcess(Process proc)throws Exception
	{
		FileOutputStream fos = new FileOutputStream("output.dat");
        StreamGobbler outputGobbler = new 
        StreamGobbler(proc.getInputStream(), "OUTPUT",fos);
        outputGobbler.start();
        int exitVal = proc.waitFor();
	}
	
	static class StreamGobbler extends Thread
	{
	    InputStream is;
	    String type;
	    OutputStream os;
	    
	    StreamGobbler(InputStream is, String type)
	    {
	        this(is, type, null);
	    }
	    StreamGobbler(InputStream is, String type, OutputStream redirect)
	    {
	        this.is = is;
	        this.type = type;
	        this.os = redirect;
	    }
	    
	    public void run()
	    {
	        try
	        {
	            InputStreamReader isr = new InputStreamReader(is);
	            BufferedReader br = new BufferedReader(isr);
	            String line=null;
	            while ( (line = br.readLine()) != null)
	            {
	            	PrintWriter pw = new PrintWriter(new FileOutputStream("output.dat"));
	                pw.println(line);
	                pw.flush();
	                pw.close();
	            }
	            
	        } 
	        catch (IOException ioe)
            {
	            ioe.printStackTrace();  
            }
	    }
	}
}
